/**
 * @class UI-条目组件-天体标签
 * @author DuskyHuang 圣子
 * @description 跟随3D天体的2D显示名称。
*/

import { _decorator, Component, Label, Camera, Color, Node, UITransform, Vec3, Prefab } from 'cc';
import { decorators, HeadUpDisplay, utils } from 'cfw';
import { CelestialNameMap } from '../../celestial';
import { LabelI18nAdvanced, CelestialNameType } from '../label-i18n-adv';
const { ccclass } = _decorator;

@ccclass('cocosmos.celestial-label')
@decorators.poolify
export class CelestialLabel extends Component implements utils.IPoolable {

    declare static readonly size: number;
    declare static claim: (type: style, name?: string) => CelestialLabel;
    declare static free: (item: CelestialLabel) => void;
    declare static clear: () => void;
    declare static dump: () => void;
    declare static template?: Prefab;
    declare static container?: Node;
    declare public free: () => void;
    private _lbl: Label = null;

    public claimed(type: style, name?: string): this {
        this.node.parent = CelestialLabel.Containers[type];
        this._adv.type = CelestialNameType.Pure;
        this.syncActive = false;
        if (name) this.node.name = name;
        return this;
    }

    public freed(): void { this._hud.target = null; }

    protected onLoad(): void {
        this._hud = this.getComponent(HeadUpDisplay);
        this._lbl = this.getComponent(Label);
        this._adv = this.getComponent(LabelI18nAdvanced);
    }

    // set i18n strings
    public setMap(map: CelestialNameMap, type: CelestialNameType.Star | CelestialNameType.Deep) { this._adv.setMapType(map, type); }
    public set key(key: i18nKey) { this._adv.key = key; }
    public set config(config: i18nConfig) { this._adv.config = config; }
    public set pure(str: string) { this._adv.pure = str; }
    public set string(arg: string) { if (this._lbl) this._lbl.string = arg; }
    public get string(): string { return this._lbl?.string; }

    public set color(arg: Color) {
        this._lbl.color = arg;
    }
    public set camera(arg: Camera) { this._hud.mainCamera = arg; }
    public set target(arg: Node) { this._hud.target = arg; }
    public get target(): Node | null { return this._hud.target; }
    public set fontSize(arg: number) { if (this._lbl) this._lbl.fontSize = this._lbl.lineHeight = arg; }
    public set alpha(arg: num.pct) {
        if (this._lbl) {
            color.set(this._lbl.color);
            if (this._lbl.cacheMode === Label.CacheMode.BITMAP) {
                color.a = Math.floor(arg * 5) / 5 * 255;
            } else color.a = arg * 255;
            this._lbl.color = color;
        }
    }
    public set char(arg: boolean) { if (this._lbl) this._lbl.cacheMode = arg ? Label.CacheMode.CHAR : Label.CacheMode.NONE; }
    public set bitmap(arg: boolean) { if (this._lbl) this._lbl.cacheMode = arg ? Label.CacheMode.BITMAP : Label.CacheMode.NONE; }
    public set scalable(arg: boolean) { this._hud.scalable = arg; }
    public set bold(arg: boolean) { if (this._lbl) this._lbl.isBold = arg; }
    public set italic(arg: boolean) { if (this._lbl) this._lbl.isItalic = arg; }
    public set alwaysInCanvas(arg: boolean) { this._hud.alwaysInCanvas = arg; }
    public set locate(arg: '中心' | `${'上' | '下'}${'左' | '右' | '标'}`) {
        this.getComponent(UITransform).setAnchorPoint(
            arg.includes('右') ? 0 : arg.includes('左') ? 1 : 0.5,
            arg.includes('上') ? 0 : arg.includes('下') ? 1 : 0.5
        );
    }
    public set perspective(arg: boolean) {
        this._hud.perspective = arg;
        this._hud.distance = 2;
        this._hud.scaleRatio = arg ? SCALE_RATIO : 1;
        this._hud.scaleRange.set(0.7, 1.5);
    }

    public get worldOffset(): Readonly<Vec3> {
        return Vec3.add(v3a, this._hud.target.worldPosition,
            Vec3.multiply(v3a, this._hud.target.worldScale, this._hud.offset));
    }

    public setOffset(v3: Vec3): this;
    public setOffset(x: number, y: number, z: number): this;
    public setOffset(arg0: Vec3 | number, y?: number, z?: number): this {
        if (isObject(arg0)) this._hud.offset.set(arg0);
        else this._hud.offset.set(arg0, y, z);
        return this;
    }

    public setUIOffset(x: number, y: number): this {
        this._hud.offsetUI.set(x, y);
        return this;
    }

    public set syncActive(arg: boolean) {
        this._hud.syncActive = arg;
    }

    private _hud: HeadUpDisplay = null;
    private _adv: LabelI18nAdvanced = null;
    public static readonly Containers: Partial<Record<style, Node>> = {};
}

const v3a = new Vec3;
const color = new Color;
const SCALE_RATIO = 0.5;